Skip to content

fix: bump fflate and stellar-sdk to resolve OSV HIGH/CRITICAL - #9653

Draft
lokesh-bitgo wants to merge 1 commit into
masterfrom
WCI-1554-vulnerability-fix
Draft

fix: bump fflate and stellar-sdk to resolve OSV HIGH/CRITICAL#9653
lokesh-bitgo wants to merge 1 commit into
masterfrom
WCI-1554-vulnerability-fix

Conversation

@lokesh-bitgo

Copy link
Copy Markdown
Contributor

Ticket: WCI-1554

Summary

The Publish Release GitHub Actions job was failing at the OSV Severity Threshold gate — 3 advisory groups scored at or above the CVSS 7.0 HIGH/CRITICAL cutoff, blocking beta/release publishing.

This PR resolves all 3 findings via real dependency upgrades (not exclusions), because in both cases the vulnerable code path is reachable in BitGo's production usage.

What was failing

Enforce Vulnerability Severity Threshold
::error:: 3 of 45 advisory group(s) at or above CVSS 7.0 (HIGH/CRITICAL). Failing the release.
  fflate@0.8.2       CVSS 7.5   GHSA-px8p-9vwx-vf98
  toml@2.3.6         CVSS 7.5   GHSA-82x6-q7mm-w9cf
  toml@2.3.6         CVSS 8.2   GHSA-v5mp-jgw5-2x6j

Root cause analysis

1. fflate@0.8.2GHSA-px8p-9vwx-vf98 (CVSS 7.5)

  • Vulnerability: unzipSync() enters an infinite loop when parsing a malformed ZIP64 archive (a central directory entry declaring compressed_size = 0xFFFFFFFF without the required ZIP64 extra field). This is a denial-of-service vector — CWE class: uncontrolled resource consumption.
  • Where it comes from: transitive dependency of jspdf (fflate: "^0.8.1"), which is a dependency of modules/key-card (used to generate PDF key cards).
  • Reachability: key-card only uses jspdf/fflate to compress and generate its own PDF output — it never calls unzipSync() on an externally-supplied archive. The vulnerable code path (decompression of untrusted ZIP data) is not exercised by our usage. This alone would justify an osv-scanner.toml exclusion (same reasoning class as this repo's existing tar/extraction exclusions), but since a patched version already exists and satisfies jspdf's own version range, we chose to fix it directly instead of adding another exclusion.
  • Fix version: fflate@0.8.3 (published 2026-07-20, patched in the same minor line, no breaking changes).

2. toml@2.3.6GHSA-82x6-q7mm-w9cf (CVSS 7.5) and GHSA-v5mp-jgw5-2x6j (CVSS 8.2)

  • GHSA-82x6-q7mm-w9cf: uncontrolled recursion. toml.parse() crashes the Node process with RangeError: Maximum call stack size exceeded on a ~5-6 KB deeply nested TOML payload (bare nested arrays or inline tables). No depth guard exists in the parser.
  • GHSA-v5mp-jgw5-2x6j: prototype pollution. toml.parse() can be tricked into writing attacker-controlled keys onto Object.prototype by routing a table path through a scalar value into __proto__.__proto__ (a duplicate-key guard desync bug in the compiler). This corrupts every object in the process — DoS, logic/auth bypass, and potentially RCE via gadgets, depending on what reads those polluted properties.
  • Where it comes from: transitive dependency of stellar-sdk@10.4.1 (toml: "^2.3.0"), used by modules/bitgo, modules/sdk-coin-xlm, modules/sdk-coin-algo, and modules/sdk-coin-hbar.
  • Reachability: stellar-sdk's Federation.Server / StellarToml resolver fetches and parses stellar.toml files from remote domains during federation/compliance address lookups (xlm.tsfederationLookupByName / federationLookupByAccountId). The domain being queried is derived from the counterparty's Stellar address, i.e. attacker-influenceable input in a real transaction flow. This is a genuinely reachable attack surface in production — unlike this repo's existing tar/minimatch exclusions, which are all dev-tooling-only or usage-mode-mismatched. An exclusion would not be appropriate here.
  • Fix version: toml has no 2.3.x patched release — the fix only exists from toml@3.0.0 onward. stellar-sdk itself doesn't offer a 10.x release with a bumped toml; the first stellar-sdk version that depends on toml@^3.0.0 is 13.0.0. This forced a major version bump of stellar-sdk (10.4.1 → 13.3.0), not just a patch.

What changed

File Change Why
package.json Added "fflate": "0.8.3" to resolutions Forces the transitive fflate dependency (via jspdf) to the patched version, same pattern already used in this block for qs, jspdf, **/sha.js, etc.
modules/bitgo/package.json "stellar-sdk": "^10.0.1""^13.0.0" Pulls in toml@^3.0.0
modules/sdk-coin-xlm/package.json "stellar-sdk": "^10.0.1""^13.0.0" Same
modules/sdk-coin-hbar/package.json "stellar-sdk": "^10.0.1""^13.0.0" Same
modules/sdk-coin-algo/package.json "stellar-sdk": "^10.0.1""^13.0.0" Same
modules/sdk-coin-xlm/src/xlm.ts 7 call-site renames (see below) stellar-sdk@13.x reorganized its exports; without this, sdk-coin-xlm fails to compile
yarn.lock Regenerated Reflects fflate@0.8.3, stellar-sdk@13.3.0, toml@3.0.0

Breaking-change fix in xlm.ts

stellar-sdk@13.x moved several exports into namespaces. sdk-coin-xlm was the only module in the codebase referencing the old paths (confirmed via a repo-wide grep across all stellar-sdk consumers: bitgo, sdk-coin-algo, sdk-coin-hbar, sdk-coin-xlm, sdk-core):

Old (stellar-sdk 10.x) New (stellar-sdk 13.x) Occurrences in xlm.ts
stellar.Server stellar.Horizon.Server 2 (getMinimumReserve, getBaseTransactionFee)
stellar.FederationServer stellar.Federation.Server 2 (getBitGoFederationServer return type and constructor call)
stellar.FederationServer.Record stellar.Federation.Api.Record 3 (federationLookup, federationLookupByName, federationLookupByAccountId return types)

These are pure rename/re-export changes on our side — no behavioral logic was touched. Mapping was confirmed directly against stellar-sdk's shipped .d.ts files (lib/index.d.ts, lib/federation/index.d.ts), not guessed.

Why not exclude instead of bump

This repo already has a well-established pattern of excluding vulnerabilities in osv-scanner.toml when the vulnerable code path is provably unreachable (e.g. 19+ existing entries for tar extraction CVEs that don't apply because BitGoJS only uses tar for packing via lerna, never extraction of untrusted archives).

That reasoning does not hold for toml/stellar-sdk: the vulnerable function (toml.parse()) is fed content from a remote server chosen by the counterparty in a federation lookup — a real, reachable, production attack surface. A version bump was the correct fix, not an exclusion.

For fflate, the unreachable-path argument does apply (key-card only compresses, never calls unzipSync()), so an exclusion would have been defensible — but since a drop-in patched version already existed with no breaking changes, fixing it directly was simpler and strictly safer than carrying a permanent exception.

Cooldown / supply-chain check

Before adopting these versions, checked publish dates against the general practice of not adopting very-recently-published packages:

Package Fix version Published Age as of fix
fflate 0.8.3 2026-07-20 ~46 days
toml 3.0.0 2026-07-14 ~52 days
stellar-sdk 13.3.0 2025-10-16 ~11 months

All three are well clear of any reasonable cooldown window (even a conservative 30-day bar).

Testing performed

  • yarn build on sdk-coin-xlm, sdk-coin-algo, sdk-coin-hbar, bitgo — all compile clean with stellar-sdk@13.3.0.
  • yarn unit-test on the 3 directly affected coin modules:
    • sdk-coin-xlm: 108 passing, 0 failing
    • sdk-coin-algo: 231 passing, 0 failing
    • sdk-coin-hbar: 233 passing, 0 failing
  • Confirmed yarn.lock resolves to fflate@0.8.3, stellar-sdk@13.3.0, toml@3.0.0.
  • Repo-wide grep confirmed no other file references the renamed stellar-sdk exports.

Known caveat

stellar-sdk@13.3.0 itself is deprecated in favor of @stellar/stellar-sdk (the package was renamed upstream; stellar-sdk@13.3.0 is still real, maintained code, just a deprecated pointer). Migrating to the renamed package is a separate, larger effort and out of scope for this fix — this PR only does the minimum version bump needed to close the CVEs.

@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

WCI-1554

@lokesh-bitgo lokesh-bitgo self-assigned this Sep 4, 2026
@lokesh-bitgo
lokesh-bitgo force-pushed the WCI-1554-vulnerability-fix branch from 0aca2d3 to 2a3bc5c Compare September 4, 2026 07:56
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ Unit tests are failing on Node 26.x (Current release line, non-blocking). This is not an LTS version yet, so it does not block merge, but it signals an incompatibility to fix before Node 26.x becomes LTS.

View run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant